package com.demarc.pesquisas.negocio.entidade.domicilio;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.Digits;
import javax.validation.constraints.NotNull;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.hibernate.annotations.Parameter;
import org.hibernate.annotations.Type;

import com.demarc.pesquisas.infraestrutura.hibernate.type.HibernateTypes;
import com.demarc.pesquisas.infraestrutura.persistencia.ObjetoPersistenteVersionado;
import com.demarc.pesquisas.negocio.entidade.BomRuimEnum;
import com.demarc.pesquisas.negocio.entidade.Endereco;
import com.demarc.pesquisas.negocio.entidade.EstadoEnum;
import com.demarc.pesquisas.negocio.entidade.SimNaoEnum;

@Entity
@Table(name = "dom_domicilio")
@AttributeOverrides(value = {
        @AttributeOverride(name = "ultimaAtualizacao", column = @Column(name = "dom_ultima_atualizacao")),
        @AttributeOverride(name = "usuarioAtualizacao", column = @Column(name = "dom_usuario_atualizacao"))})
public class Domicilio extends ObjetoPersistenteVersionado<Long> {

    public static final String ID = "dom_id";

    private Long id;
    private Endereco endereco;
    private List<Morador> moradores;
    private Integer quantResidentes;
    private Integer quantComodos;
    private Integer quantAposentadosRecebemPensao;
    private Integer quantPessoasRecebemBeneficio;
    private TipoMaterialPredominanteConstrucaoEnum tipoMaterialConstrucaoPredominante;
    private String outroMaterialConstrucao;
    private TipoBanheiroEnum tipoBanheiro;
    private SimNaoEnum possuiSisterna;
    private SimNaoEnum possuiPoco;
    private BomRuimEnum tipoVazaoPoco;
    private TipoTerrenoEnum tipoTerreno;
    private SimNaoEnum todosMoradoresPossuemRegistroCivil;
    private Integer quantMoradoresPossuemRegistroCivil;
    private SimNaoEnum todosMoradoresPossuemRG;
    private Integer quantMoradoresPossuemRG;
    private SimNaoEnum todosMoradoresPossuemCPF;
    private Integer quantMoradoresPossuemCPF;
    private SimNaoEnum todosMoradoresACima16AnosPossuemTituloEleitor;
    private Integer quantMoradoresACima16AnosPossuemTituloEleitor;
    private BigDecimal rendaFamiliar;
    private Integer quantPessoasTrabalham;
    private Integer quantPessoasNaoSabemLerOuEscrever;
    private SimNaoEnum necessitaCartao;

    public Domicilio() {
        this(new Endereco(EstadoEnum.PERNAMBUCO, "Inajá"));
    }

    public Domicilio(Endereco endereco) {
        this.endereco = endereco;
        this.moradores = new ArrayList<Morador>();
    }

    public void adicionarMorador(Morador morador) {
        if (morador != null) {
            morador.setDomicilio(this);
            this.moradores.add(morador);
        }
    }

    public void removerMorador(Morador morador) {
        if (morador != null) {
            this.moradores.remove(morador);
        }
    }

    @Id
    @Column(name = ID)
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @AttributeOverrides({
            @AttributeOverride(name = "localidade", column = @Column(name = "dom_localidade", nullable = false)),
            @AttributeOverride(name = "tipoLocalidade", column = @Column(name = "dom_tipo_Localidade", nullable = false)),
            @AttributeOverride(name = "rua", column = @Column(name = "dom_rua")),
            @AttributeOverride(name = "bairro", column = @Column(name = "dom_bairro")),
            @AttributeOverride(name = "cidade", column = @Column(name = "dom_cidade")),
            @AttributeOverride(name = "estado", column = @Column(name = "dom_estado")),
            @AttributeOverride(name = "numero", column = @Column(name = "dom_numero")),
            @AttributeOverride(name = "complemento", column = @Column(name = "dom_complemento")),
            @AttributeOverride(name = "cep", column = @Column(name = "dom_cep"))})
    public Endereco getEndereco() {
        return endereco;
    }

    public void setEndereco(Endereco endereco) {
        this.endereco = endereco;
    }

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "domicilio", cascade = CascadeType.ALL, orphanRemoval = true)
    public List<Morador> getMoradores() {
        return moradores;
    }

    public void setMoradores(List<Morador> moradores) {
        this.moradores = moradores;
    }

    @Column(name = "dom_quant_residentes", nullable = false)
    @NotNull
    public Integer getQuantResidentes() {
        return quantResidentes;
    }

    public void setQuantResidentes(Integer quantResidentes) {
        this.quantResidentes = quantResidentes;
    }

    @Column(name = "dom_quant_comodos", nullable = false)
    @NotNull
    public Integer getQuantComodos() {
        return quantComodos;
    }

    public void setQuantComodos(Integer quantComodos) {
        this.quantComodos = quantComodos;
    }

    @Column(name = "dom_quant_aposent_recebem_pensao", nullable = false)
    @NotNull
    public Integer getQuantAposentadosRecebemPensao() {
        return quantAposentadosRecebemPensao;
    }

    public void setQuantAposentadosRecebemPensao(Integer quantAposentadosRecebemPensao) {
        this.quantAposentadosRecebemPensao = quantAposentadosRecebemPensao;
    }

    @Column(name = "dom_quant_pessoas_recebem_benef", nullable = false)
    @NotNull
    public Integer getQuantPessoasRecebemBeneficio() {
        return quantPessoasRecebemBeneficio;
    }

    public void setQuantPessoasRecebemBeneficio(Integer quantPessoasRecebemBeneficio) {
        this.quantPessoasRecebemBeneficio = quantPessoasRecebemBeneficio;
    }

    @Enumerated(EnumType.STRING)
    @Column(name = "dom_tipo_material_constr", nullable = false)
    @NotNull
    public TipoMaterialPredominanteConstrucaoEnum getTipoMaterialConstrucaoPredominante() {
        return tipoMaterialConstrucaoPredominante;
    }

    public void setTipoMaterialConstrucaoPredominante(
            TipoMaterialPredominanteConstrucaoEnum tipoMaterialConstrucaoPredominante) {
        this.tipoMaterialConstrucaoPredominante = tipoMaterialConstrucaoPredominante;
    }

    @Column(name = "dom_outro_material_constr")
    public String getOutroMaterialConstrucao() {
        return outroMaterialConstrucao;
    }

    public void setOutroMaterialConstrucao(String outroMaterialConstrucao) {
        this.outroMaterialConstrucao = outroMaterialConstrucao;
    }

    @Type(type = HibernateTypes.ENUM_INTEGER_USER_TYPE, parameters = {@Parameter(name = HibernateTypes.ENUM_CLASS, value = TipoBanheiroEnum.CLASS_NAME)})
    @Column(name = "dom_tipo_banheiro", nullable = false)
    @NotNull
    public TipoBanheiroEnum getTipoBanheiro() {
        return tipoBanheiro;
    }

    public void setTipoBanheiro(TipoBanheiroEnum tipoBanheiro) {
        this.tipoBanheiro = tipoBanheiro;
    }

    @Enumerated(EnumType.STRING)
    @Column(name = "dom_possui_sisterna", nullable = false)
    @NotNull
    public SimNaoEnum getPossuiSisterna() {
        return possuiSisterna;
    }

    public void setPossuiSisterna(SimNaoEnum possuiSisterna) {
        this.possuiSisterna = possuiSisterna;
    }

    @Enumerated(EnumType.STRING)
    @Column(name = "dom_possui_poco", nullable = false)
    @NotNull
    public SimNaoEnum getPossuiPoco() {
        return possuiPoco;
    }

    public void setPossuiPoco(SimNaoEnum possuiPoco) {
        this.possuiPoco = possuiPoco;
    }

    @Enumerated(EnumType.STRING)
    @Column(name = "dom_tipo_vazao_poco")
    public BomRuimEnum getTipoVazaoPoco() {
        return tipoVazaoPoco;
    }

    public void setTipoVazaoPoco(BomRuimEnum tipoVazaoPoco) {
        this.tipoVazaoPoco = tipoVazaoPoco;
    }

    @Type(type = HibernateTypes.ENUM_INTEGER_USER_TYPE, parameters = {@Parameter(name = HibernateTypes.ENUM_CLASS, value = TipoTerrenoEnum.CLASS_NAME)})
    @Column(name = "dom_tipo_terreno", nullable = false)
    @NotNull
    public TipoTerrenoEnum getTipoTerreno() {
        return tipoTerreno;
    }

    public void setTipoTerreno(TipoTerrenoEnum tipoTerreno) {
        this.tipoTerreno = tipoTerreno;
    }

    @Enumerated(EnumType.STRING)
    @Column(name = "dom_todos_moradores_possuem_rc")
    public SimNaoEnum getTodosMoradoresPossuemRegistroCivil() {
        return todosMoradoresPossuemRegistroCivil;
    }

    public void setTodosMoradoresPossuemRegistroCivil(SimNaoEnum todosMoradoresPossuemRegistroCivil) {
        this.todosMoradoresPossuemRegistroCivil = todosMoradoresPossuemRegistroCivil;
    }

    @Column(name = "dom_quant_moradores_possuem_rc")
    public Integer getQuantMoradoresPossuemRegistroCivil() {
        return quantMoradoresPossuemRegistroCivil;
    }

    public void setQuantMoradoresPossuemRegistroCivil(Integer quantMoradoresPossuemRegistroCivil) {
        this.quantMoradoresPossuemRegistroCivil = quantMoradoresPossuemRegistroCivil;
    }

    @Enumerated(EnumType.STRING)
    @Column(name = "dom_todos_moradores_possuem_rg")
    public SimNaoEnum getTodosMoradoresPossuemRG() {
        return todosMoradoresPossuemRG;
    }

    public void setTodosMoradoresPossuemRG(SimNaoEnum todosMoradoresPossuemRG) {
        this.todosMoradoresPossuemRG = todosMoradoresPossuemRG;
    }

    @Column(name = "dom_quant_moradores_possuem_rg")
    public Integer getQuantMoradoresPossuemRG() {
        return quantMoradoresPossuemRG;
    }

    public void setQuantMoradoresPossuemRG(Integer quantMoradoresPossuemRG) {
        this.quantMoradoresPossuemRG = quantMoradoresPossuemRG;
    }

    @Enumerated(EnumType.STRING)
    @Column(name = "dom_todos_moradores_possuem_cpf")
    public SimNaoEnum getTodosMoradoresPossuemCPF() {
        return todosMoradoresPossuemCPF;
    }

    public void setTodosMoradoresPossuemCPF(SimNaoEnum todosMoradoresPossuemCPF) {
        this.todosMoradoresPossuemCPF = todosMoradoresPossuemCPF;
    }

    @Column(name = "dom_quant_moradores_possuem_cpf")
    public Integer getQuantMoradoresPossuemCPF() {
        return quantMoradoresPossuemCPF;
    }

    public void setQuantMoradoresPossuemCPF(Integer quantMoradoresPossuemCPF) {
        this.quantMoradoresPossuemCPF = quantMoradoresPossuemCPF;
    }

    @Enumerated(EnumType.STRING)
    @Column(name = "dom_todos_moradores_possuem_titulo", nullable = false)
    @NotNull
    public SimNaoEnum getTodosMoradoresACima16AnosPossuemTituloEleitor() {
        return todosMoradoresACima16AnosPossuemTituloEleitor;
    }

    public void setTodosMoradoresACima16AnosPossuemTituloEleitor(
            SimNaoEnum todosMoradoresACima16AnosPossuemTituloEleitor) {
        this.todosMoradoresACima16AnosPossuemTituloEleitor =
                todosMoradoresACima16AnosPossuemTituloEleitor;
    }

    @Column(name = "dom_quant_moradores_possuem_titulo_eleitor", nullable = false)
    @NotNull
    public Integer getQuantMoradoresACima16AnosPossuemTituloEleitor() {
        return quantMoradoresACima16AnosPossuemTituloEleitor;
    }

    public void setQuantMoradoresACima16AnosPossuemTituloEleitor(
            Integer quantMoradoresACima16AnosPossuemTituloEleitor) {
        this.quantMoradoresACima16AnosPossuemTituloEleitor =
                quantMoradoresACima16AnosPossuemTituloEleitor;
    }

    @Digits(integer = 10, fraction = 2)
    @Column(name = "dom_renda_familiar", columnDefinition = "decimal(10,2)", nullable = false)
    @NotNull
    public BigDecimal getRendaFamiliar() {
        return rendaFamiliar;
    }

    public void setRendaFamiliar(BigDecimal rendaFamiliar) {
        this.rendaFamiliar = rendaFamiliar;
    }

    @Column(name = "dom_quant_pessoas_trabalham", nullable = false)
    @NotNull
    public Integer getQuantPessoasTrabalham() {
        return quantPessoasTrabalham;
    }

    public void setQuantPessoasTrabalham(Integer quantPessoasTrabalham) {
        this.quantPessoasTrabalham = quantPessoasTrabalham;
    }

    @Column(name = "dom_quant_pessoas_nao_sabem_ler_escrever", nullable = false)
    @NotNull
    public Integer getQuantPessoasNaoSabemLerOuEscrever() {
        return quantPessoasNaoSabemLerOuEscrever;
    }

    public void setQuantPessoasNaoSabemLerOuEscrever(Integer quantPessoasNaoSabemLerOuEscrever) {
        this.quantPessoasNaoSabemLerOuEscrever = quantPessoasNaoSabemLerOuEscrever;
    }

    @Enumerated(EnumType.STRING)
    @Column(name = "dom_necessita_cartao", nullable = false)
    @NotNull
    public SimNaoEnum getNecessitaCartao() {
        return necessitaCartao;
    }

    public void setNecessitaCartao(SimNaoEnum necessitaCartao) {
        this.necessitaCartao = necessitaCartao;
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder().append(this.endereco).append(this.moradores).toHashCode();
    }

    @Override
    public boolean equals(Object obj) {
        boolean isEquals = false;

        if (obj == this) {
            isEquals = true;
        } else if (obj instanceof Domicilio) {
            Domicilio domicilio = (Domicilio) obj;
            isEquals =
                    new EqualsBuilder().append(this.endereco, domicilio.getEndereco())
                            .append(this.moradores, domicilio.getMoradores()).isEquals();
        }
        return isEquals;
    }
}
